home *** CD-ROM | disk | FTP | other *** search
- FAQPAS2.TXT More frequently (and not so frequently) asked Turbo
- Pascal questions with Timo's answers.
-
- ..................................................................
- Prof. Timo Salmi Co-moderator of comp.archives.msdos.announce
- Moderating at garbo.uwasa.fi anonymous FTP archives 128.214.87.1
- Faculty of Accounting & Industrial Management; University of Vaasa
- Internet: ts@uwasa.fi Bitnet: salmi@finfun; FI-65101, Finland
-
- -------------------------------------------------------------------
- 31) How does one store, and then restore the original screen?
- 32) How can I convert a TPU unit of one TP version to another?
- 33) Which error is e.g. Runtime error 205, etc
- 34) Why can't I open read-only files? I get "File access denied".
- 35) How do I obtain high and low parts of a byte variable?
- 36) How can I set a hi-intensity color background in the text mode?
- 37) Where can I find a program to convert (Turbo) Pascal to C?
- 38) How can I read input without echoing to the screen?
- 39) How can I edit the readln input stream?
- 40) How can I write (brand) something into my executables?
- 41) What is wrong with my program? It hangs without a clear pattern?
- 42) How do I convert a decimal word into a hexadecimal string, etc?
- 43) How to determine the last drive?
- 44) How can I put a running clock into my Turbo Pascal program?
- 45) How to establish if a name refers to a directory or not?
- 46) How does one disable alt-ctrl-del?
- 47) How can I test whether a file exists?
- 48) What is the name of the current Turbo Pascal program?
- 49) How is the code for rebooting the PC written in Turbo Pascal?
- 50) How can I write inline code?
- 51) I am running out of memory when compiling my large program.
- 52) How do I avoid scrolling in the last column of the last row?
- -------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:31 1993
- Subject: Saving the screen
-
- 31. *****
- Q: How does one store, and then restore the original screen?
-
- A: Here is a simple outline for storing and restoring a text mode
- screen. Note that the code below is incomplete in a sense that it
- works for a color monitor only, because the monochrome screen
- address is $B000:$0000.
- For storing and restoring the graphics screen see Ohlsen & Stoker
- (1989), Turbo Pascal Advanced Techniques, Que, pp 333-337.
- uses Crt;
- type ScreenType = array [1..4000] of byte; (* 2 x 80 x 25 *)
- var ColorScreen : ScreenType Absolute $B800:$0000;
- SavedScreen : ScreenType;
- posx, posy : byte;
- begin
- SavedScreen := ColorScreen; (* Save the screen *)
- posx := WhereX; posy := WhereY; (* Save the cursor position *)
- writeln ('A simple demo storing and restoring the color text screen');
- writeln ('By Prof. Timo Salmi, ts@uwasa.fi');
- writeln; write ('Press <-'''); readln;
- ColorScreen := SavedScreen; (* Restore the screen *)
- GotoXY(posx,posy); (* Go to the stored cursor position *)
- end.
- If you would prefer not using the Crt unit, you can apply WHEREXFN,
- WHEREYFN, and GOATXY from TSUNTG.TPU from /pc/ts/tspa33*.zip.
- Likewise, if you wish to test for the monitor type, that is choose
- between $B800:$0000 and $B000:$0000 bases, you can use
- MONOFN "Is it a monochrome video adapter"
- in the said units collection.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:32 1993
- Subject: Converting TPUs
-
- 32. *****
- Q: How can I convert a TPU unit of one TP version to another?
-
- A: Forget it. In practical terms such a conversion is not on. The
- Turbo Pascal TPU units are strictly version dependent. If there were
- a working solution I assume we would have heard of it long since.
- The hacks that have been tried won't solve this dilemma. For all
- practical purposes you need the source code and the relevant
- compiler version.
- You may nevertheless wish to ascertain for which version a TPU
- unit has been compiled. This is very simple. Just look at the first
- four character of a TPU file. The codes are
- TPU0 for 4.0
- TPU5 for 5.0
- TPU6 for 5.5
- TPU9 for 6.0
- TPUQ for 7.0 real mode
- But don't go editing these. It will not get you anywhere.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:33 1993
- Subject: Finding about runtime errors
-
- 33. *****
- Q: Which error is e.g. Runtime error 205
-
- A: Basically this is a case of RTFM (read the f*ing manual). But it
- is very easy to find out even without resorting to the manual. Put
- temporarily the statement RunError (205); as the first statement of
- your program. Then run your program from the Turbo Pascal IDE, that
- is from within the TP editor. The description of the error will
- appear.
- If you run a program from within a Turbo Pascal IDE, it is
- advisable to turn on the debug options on. You'll get both the error
- number and the description. Furthermore by pressing F1 after the
- error you get its description in a more verbal format.
- One further trick is to put "uses TSERR"; (Include verbal
- run-time error messages) into your program. If you do that, the
- run-time errors will be given with a verbal description not just as
- a number. TSERR.TPU is part of my TPU collection /pc/ts/tspa*.zip.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:34 1993
- Subject: Opening read-only files
-
- 34. *****
- Q: Why can't I open read-only files? I get "File access denied".
-
- A: The answer is rather simple, but it is not well displayed in the
- manuals. In order to read a read-only file you have to set the
- FileMode as 0 like below. Else you'll get runtime error 005 "File
- access denied".
- var f : text; (* Can be any file type *)
- savefm : byte;
- begin
- savefm := FileMode; (* Save the current FileMode status *)
- FileMode := 0; (* The default is 2 *)
- assign (f, 'readonly.txt');
- reset (f);
- { have your wicked ways }
- close (f);
- FileMode := savefm; (* Restore the original FileMode *)
- end.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:35 1993
- Subject: Getting a nybble from a byte
-
- 35. *****
- Q: I have a variable of type BYTE and would like to extract two
- numbers from it. (The first 4 bits making up number A, the second 4
- bits making up number B). How can I extract these two numbers?
-
- A: Ah, this questions bring back the good bad old days of the
- Commodore C64 programming when bit operations were rather a rule
- than a exception. Here is the solution.
- function HIBYTEFN (x : byte) : byte;
- begin
- hibytefn := x Shr 4; (* Shift right by four bits *)
- end;
- {}
- function LOBYTEFN (x : byte) : byte;
- begin
- lobytefn := x and 15; (* x and 00001111 *)
- end;
- From Patrick Taylor (exuptr@exu.ericsson.se): Ah, leave it to Timo
- to come up with a different way! An other is (n div 16)
- (n mod 16).
- Patrick is right. But unless the compiler is optimized, the
- former produces more efficient code. Not that it really makes any
- practical difference whatsoever.
- Of course the fastest code is produced using assembler as pointed
- out by Maarten Pennings (maarten@cs.ruu.nl) who provided the
- following inline example:
- function high(b:byte):byte;
- inline($58 { POP AX | AH=?, AL=b }
- /$30/$e4 { XOR AH,AH | AH=0, AL=b }
- /$b9/$04/$00 { MOV CX,0004 | AH=0, AL=b, CL=4 }
- /$d3/$e8 { SHR AX,CL | AX=b shr 4 }
- );
-
- A2: Getting a word from a longint can alternatively be achieved
- without any calculations by using a kind of typecasting. Below is
- the code I have utilized in garbo.uwasa.fi:/pc/tspa*.zip.
- (* Get the high-order word of the longint argument *)
- function HIWORDFN (x : longint) : word;
- type type1 = record
- low : word;
- high : word;
- end;
- var m1 : type1 absolute x;
- begin
- hiwordfn := m1.high;
- end; (* hiwordfn *)
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:36 1993
- Subject: Setting hi-intensity background
-
- 36. *****
- Q: How can I set a hi-intensity color background in the text mode?
-
- A: As you should know, the you can test for a blinking text for
- example as follows.
- uses Crt;
- begin
- TextColor (11 + 128); (* or LightCyan + Blink *)
- TextBackground (Blue);
- writeln ('What''s the catch?'); (* An aside, note the '' pair *)
- end.
- In the above, bit 7 (the 128) controls the blinking. If you have at
- least an EGA, you can alter the interpretation of the highest text
- color bit to denote a hi-intensity background, but then you lose the
- the blinking. The following piece of code disables blinking,
- enabling a hi-intensity background.
- uses Dos;
- var regs : registers;
- begin
- FillChar (regs, SizeOf(regs), 0); (* An initialization precaution *)
- regs.ah := $10; (* Function $10 *)
- regs.al := $03; (* Subfunction $03 *)
- regs.bl := $00;
- Intr ($10, regs); (* ROM BIOS video driver interrupt *)
- end.
- To enable blinking again, set regs.bl := $01; Any high-intensity
- background you may have currently on the screen, will instantly
- change into a blinking text a a low-intensity background.
-
- A2: The previous answer assumes at least an EGA. Otherwise ports
- must be accessed. This is both advanced and dangerous programming,
- because errors in handling posts can do real harm. Besides it is
- fair to require at least an EGA in writing modern programs, at least
- for non-laptops, and on the latter the colors don't really matter
- for CGA and below. Let's take a look, nevertheless, how this is done
- for a CGA. Note that this won't work an an EGA and beyond, not at
- least in my tests. For detecting the video adapter you have, see the
- DetectGraph procedure in you Turbo Pascal manual.
- First we need some basics from MEMORY.LST in Ralf Brown's
- garbo.uwasa.fi:/pc/programming/inter35b.zip (or whatever version is
- current):
- Format of BIOS Data Segment at segment 40h:
- 63h WORD Video CRT controller base address: color=03D4h, mono=03B4h
- 65h BYTE Video current setting of mode select register 03D8h/03B8h
- From David Jurgens's /pc/programming/helppc21.zip we see
- 3D0-3DF Color Graphics Monitor Adapter (ports 3D0-3DB are
- write only, see 6845)
- 3D8 6845 Mode control register (CGA, EGA, VGA, except PCjr)
- From Darryl Friesen's (friesend@jester.usask.ca) in comp.lang.pascal
- we have, the following procedure, with my own added comments (* *).
- procedure SetBlinkState (state : boolean);
- var ModeRegPort : word;
- ModeReg : byte;
- begin
- Inline($FA); { CLI } (* Interrupts off *)
- ModeRegPort := MemW[$0040:$0063]+4; (* Typically $03D4+4 = $03D8 *)
- ModeReg := Mem[$0040:$0065]; (* Typically 1001 *)
- if state then (* Bit 5 controls blink enable *)
- ModeReg := ModeReg or $20 (* $20 = 00100000 (base2) *)
- else
- ModeReg := ModeReg and $DF; (* $DF = 11011111 disable *)
- Port[ModeRegPort] := ModeReg; (* Typically $9 = 00001001 *)
- Mem[$0040:$0065] := ModeReg; (* or $29 = 00101001 *)
- Inline($FB) { STI } (* Interrupts on *)
- end;
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:37 1993
- Subject: Pascal to C
-
- 37. *****
- Q: Where can I find a program to convert (Turbo) Pascal to C?
-
- A: This is a relevant question, but I have placed elsewhere the
- tips on the "looking for a program" questions. Here are the
- pointers to further pointers :-). (The FAQ versions might have been
- updated since I wrote this.)
- garbo.uwasa.fi:/pc/pd2/camfaq.zip
- camfaq.zip comp.archives.msdos.(d/announce) FAQ (general finding)
- :
- garbo.uwasa.fi:/pc/pd2/tsfaqn37.zip
- tsfaqn37.zip Questions from UseNet and Timo's answers
- :
- garbo.uwasa.fi:/pc/pd2/faquote.zip
- faquote.zip Old information from tsfaq Frequently Asked Questions
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:38 1993
- Subject: Turning off the input echo
-
- 38. *****
- Q: How can I read input without echoing to the screen?
-
- A: It is fairly simple. Study this example source code, with the
- manual, if need be.
- uses Crt;
- var password : string;
- {}
- (* Read without echoing *)
- procedure GETPASS (var s : string);
- var key : integer;
- ch : char;
- begin
- s := '';
- repeat
- ch := ReadKey; key := ord (ch);
- case key of
- 0 : ch := ReadKey; (* Discard two-character keys, like F1 *)
- 13 : exit; (* Enter has been pressed *)
- 1..12,13..31,255 :; (* Discard the special characters *)
- else s := s + ch;
- end;
- until false;
- end; (* getpass *)
- {}
- (* The main program *)
- begin
- write ('Password: ');
- GETPASS (password);
- writeln;
- writeln (password);
- end.
- {}
- If you wish to be able to edit the input stream, like having the
- BackSpace functional, that is more complicated, and is left as an
- exercise after these basics. A hint: 8 : Delete (s, Length(s), 1);
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:39 1993
- Subject: Input line-editing
-
- 39. *****
- Q: How can I edit the readln input stream?
-
- A: In practice, if you wish to use anything beyond simple the
- BackSpace deleting, you'll have to build your own line editing
- routines expanding on the code in the previous item. It is quite a
- task, and you can alternatively find the preprogrammed routines in
- my Turbo Pascal units tspa33*.zip (or whatever version number is
- current).
- EDRDEBLN Editable Readln with ctrl-c, break trapping, pre-fill etc
- EDRDEFLN Editable Readln with recall, pre-fill, and insert toggle
- EDRDLN Readln with line-editing potential (the simplest)
- EDREABLN Edreadln with ctrl-c and break trapping
- EDREADLN Editable Readln with recall, and insert toggle
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:40 1993
- Subject: Executable branding
-
- 40. *****
- Q: How can I write (brand) something into my executables?
- Here is the actual question that led me to writing this item: 'I
- am very interested in the .EXE "branding" techniques you use in
- your TSUNTI unit. Would it be possible to get hold of the source
- code for that unit, as it would save me from having to re-invent
- the wheel?'
-
- A: What you are referring to is
- BRANDEXE Store information within your program's .exe file (MsDos 3.0+)
- CHKSUMFN Checksum selftest to detect any tampering (MsDos 3.0+)
- USECOUNT Get the number of times the program has been used
- Sorry no, I don't want to distribute my /pc/turbopas/tspa33*.zip
- source codes. Besides they would be less useful to you than you may
- think because internally my programs are in Finnish, comments,
- variable and procedure names, and all. But I can hopefully help you
- by giving a reference to a similar code. Please see Ohlsen &
- Stoker, Turbo Pascal Advanced Techniques, Que, 1989, p. 420.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:41 1993
- Subject: Elusive, inconsistent errors
-
- 41. *****
- Q: What is wrong with my program? It hangs without a clear pattern?
-
- A: With experience one learns that some programming errors are very
- elusive. I have many times seen users declaring that they have found
- a bug in Turbo Pascal, but in the overwhelming majority of cases it
- still is just a programming error, which just is more difficult to
- find than the more clear-cut cases. When you have symptoms like your
- program crashing from within the IDE, but working seemingly all
- right when called as stand-alone, or something equally strange, you
- might have one of the following problems.
- - A variable or some variables in your code are uninitialized thus
- getting random values, which differ depending on your environment.
- - Your indexes are overflowing. Set on the range check {$R+}
- directive for testing.
- - An error in the pointer logic.
- Normal debugging does not necessarily help in locating these errors
- because one is easily led to debugging the wrong parts of one's
- program. Especially the latter two reasons can cause errors which
- seemingly have nothing to do with the actual cause. This results
- from the fact that indexing and pointer errors can overwrite parts
- of memory causing strange quirks in your program. If you have used
- indexing with {$R-} or if you use pointer operations, sooner or
- later you are bound to have these problems in developing your
- applications.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:42 1993
- Subject: Converting the number base
-
- 42. *****
- Q: How do I convert a decimal word into a hexadecimal string, etc?
-
- A: Here is one possibility
- function HEXFN (decimal : word) : string;
- const hexDigit : array [0..15] of char = '0123456789ABCDEF';
- begin
- hexfn := hexDigit[(decimal shr 12)]
- + hexDigit[(decimal shr 8) and $0F]
- + hexDigit[(decimal shr 4) and $0F]
- + hexDigit[(decimal and $0F)];
- end; (* hexfn *)
- Here is another conversion example (from longint to binary string)
- function LBINFN (decimal : longint) : string;
- const BinDigit : array [0..1] of char = '01';
- var i : byte;
- binar : string;
- begin
- FillChar (binar, SizeOf(binar), ' ');
- binar[0] := chr(32);
- for i := 0 to 31 do
- binar[32-i] := BinDigit[(decimal shr i) and 1];
- lbinfn := binar;
- end; (* lbinfn *)
- For a full set of conversions, both from and to decimal, apply
- TSUTNTB.TPU from garbo.uwasa.fi:/pc/ts/tspa*.zip.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:43 1993
- Subject: Identifying the last drive
-
- 43. *****
- Q: How to determine the last drive?
-
- A: One way of doing that is utilizing the information in DPB, that
- is the Drive Parameter Block, but that is rather complicated, so you
- can find that without source code in garbo.uwasa.fi:/pc/ts/tspa*.zip
- in the TSUNTH unit.
- Another way is using interrrupt 21H, function 36H to detect if a
- drive exists starting from the first drive letter. The code is given
- below. The disadvantage of this method is that it does not
- distinguish between real and substituted drives.
- uses Dos;
- function LASTDFN : char; (* Detect last harddisk letter *)
- var regs : registers;
- i : byte;
- begin
- i := 2;
- repeat
- Inc(i);
- FillChar (regs, SizeOf(regs), 0);
- regs.ah := $36;
- regs.dl := i;
- MsDos(regs);
- until (regs.ax = $FFFF);
- lastdfn := chr(i+63);
- end; (* lastdfn *)
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:44 1993
- Subject: Clock display in a TP program
-
- 44. *****
- Q: How can I put a running clock into my Turbo Pascal program?
-
- A: We are not speaking of a stand-alone TSR-clock (which is a
- different task), but considering a clock that continuously displays
- the time in some part of the output screen of your Turbo Pascal
- program.
- You might first want to read the earlier items about ReadKey
- usages if you are not familiar with it (you probably are, because
- you would not pose this advanced question if you were a novice). The
- items are the unlikely "How do I disable or capture the break key in
- Turbo Pascal?" and "How can I read input without echoing to the
- screen?"
- The general idea is to make the body of the program a repeat
- until loop using ReadKey for input and updating the clock display
- at suitable junctions within the loop. The scheme is thus something
- like the following.
- procedure showtime;
- begin
- { if the second has changed, write the time }
- end;
- :
- repeat
- { do whatever }
- showtime;
- if KeyPressed then
- case ReadKey of
- { whatever }
- { exit rules }
- end;
- showtime;
- :
- showtime;
- until false;
- One trick of the trade is that you must not update your clock
- each time the clock routine is encountered. You should test if the
- second has changed, and update only then. Else you are liable to get
- an annoying flicker in your clock.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:45 1993
- Subject: Is a name a directory
-
- 45. *****
- Q: How to establish if a name refers to a directory or not?
-
- A: This question has turned out a bit more complicated than I first
- thought. There are several methods, each with some catch. The first
- is trying to open the name as a file and observing the IOResult. The
- ISDIRFN function in garbo.uwasa.fi:/pc/ts/tspa*.zip TPU unit
- TSUNTJ.TPU is based on this method. Unfortunately it is not always
- stable. I have been reported problems in connection with DRDOS by
- Richard Breuer (ricki@pool.informatik.rwth-aachen.de) who has
- tested these routines.
- The second method (ISDIR2FN) is based on the fact that the file
- NUL exists in a directory if the directory exists.
- The thrid method (ISDIR3FN) is a brute force method. It is given
- below, since it is quite an instructive little exercise of Turbo
- Pascal programming.
- (* Search recursively through a drive's directories.
- Auxiliary, recursive procedure for ISDIR3FN *)
- procedure SEARCHDR (Path, FileSpec : string;
- name : string;
- var found : boolean);
- var FileInfo : SearchRec;
- begin
- FindFirst (Path + '*.*', Directory, FileInfo);
- while DosError = 0 do
- begin
- if ((FileInfo.Attr and Directory) > 0) and
- (FileInfo.Name <> '.') and
- (FileInfo.Name <> '..') then
- begin
- SEARCHDR (Path + FileInfo.Name + '\',
- FileSpec,
- name,
- found);
- if Path + FileInfo.Name + '\' = name then
- found := true;
- end;
- FindNext (FileInfo);
- end; {while}
- end; (* searchdr *)
-
- (* Does a name refer to a directory *)
- function ISDIR3FN (name : string) : boolean;
- var drive : char;
- found : boolean;
- begin
- {... Default value ...}
- isdir3fn := false;
- {... Discard empty names ...}
- if name = '' then exit;
- {... Expand into a fully qualified name, makes it uppercase ...}
- name := FExpand (name);
- if name[Length(name)] <> '\' then name := name + '\';
- {... Extract the drive letter from the name ...}
- drive := UpCase (name[1]);
- {... Check first for the root ...}
- if drive + ':\' = name then
- begin isdir3fn := true; exit; end;
- {... Check the rest of the directories recursively ...}
- found := false;
- SEARCHDR (drive + ':\', '*.*', name, found);
- isdir3fn := found;
- end; (* isdir3fn *)
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:46 1993
- Subject: Disabling alt-ctrl-del
-
- 46. *****
- Q: How does one disable alt-ctrl-del?
-
- A: I can only give a pointer to source code. Take a look at the
- code by Mikko Hanninen in garbo.uwasa.fi:/pc/turbopas/cadthf10.zip.
- I have utilized alt-ctrl-del disabling at least in one of my own
- programs (PESTIKID.EXE). The code is not available, but the general
- idea is replacing the old keyboard interrupt ($09) with a handler of
- one's own. If the handler detects alt-ctrl-del, the keyboard is
- reset, else the handler is chained back to the original interrupt.
- The chaining requires a rather complicated inline procedure provided
- in TurboPower Software's kit. An additional complication is that the
- del keypress must be intercepted already at the relevant port $60,
- and the alt and ctrl status must be tested, so that the rebooting
- will not be invoked. Resetting the keyboard requires accessing the
- $20 and $61 ports.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:47 1993
- Subject: Does a file exist
-
- 47. *****
- Q: How can I test whether a file exists?
-
- A: There are several alternatives. Here is the most common with
- example code. It recognizes also read-only, hidden and system files.
- function FILEXIST (name : string) : boolean;
- var fm : byte;
- f : file;
- b : boolean;
- begin
- fm := FileMode;
- FileMode := 0;
- assign (f, name);
- {$I-} reset(f); {$I+}
- b := IOResult = 0;
- if b then close(f);
- filexist := b;
- FileMode := fm;
- end;
-
- A second alternative is
- Uses Dos;
- function FILEXIST (name : string) : boolean;
- var f : file;
- a : word;
- begin
- assign (f, name);
- GetFAttr (f, a);
- filexist := false;
- if DosError = 0 then
- if ((a and Directory) = 0) and ((a and VolumeId) = 0) then
- filexist := true;
- end;
-
- A third alternative is
- Uses Dos;
- function FILEXIST (name : PathStr) : boolean;
- begin
- filexist := FSearch (name, '') <> '';
- end;
-
- A fourth alternative is the following. Be careful with this option,
- since it works a bit differently from the others. It accepts wild
- cards. Thus, for example FILEXIST('c:\autoexec.*') would be TRUE in
- this method, while FALSE in all the above.
- Uses Dos;
- function FILEXIST (name : string) : boolean;
- var f : SearchRec;
- begin
- filexist := false;
- FindFirst (name, AnyFile, f);
- if DosError = 0 then
- if (f.attr <> Directory) and (f.attr <> VolumeId) then
- filexist := true;
- end;
- A good variation from KDT@newton.national-physical-lab.co.uk of this
- theme, disallowing wildcards:
- function file_exists (fname :string) :boolean;
- var f :searchrec;
- begin
- findfirst (fname, anyfile - directory - volumeid, f);
- file_exists := (doserror + pos('*',fname) + pos('?',fname) = 0);
- end;
-
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:48 1993
- Subject: The current program name
-
- 48. *****
- Q: What is the name of the current Turbo Pascal program?
-
- A: The name of the currently executing Turbo Pascal program is in
- ParamStr(0).
- This was introduced in TP version 5.0, and as far as I recall at
- least MsDos version 3.0 is required. For TP 4.0 you can use
- "ParamStr0 The name of the program" from TSUNT45 in garbo.uwasa.fi:
- /pc/ts/tspa3340.zip (or whatever the version number is the latest).
- It is advisable to put the value into a string variable at be
- beginning of the program before eny I/O takes place. Thus you might
- wish to use:
- var progname : string;
- begin { the main program }
- progname := ParamStr(0);
- :
- A bonus of this method is that you can access the individual
- characters of progname (e.g. progname[1] for the drive) while that
- is not possible to do for the ParamStr keyword.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:49 1993
- Subject: How can a program reboot my PC?
-
- 49. *****
- Q: How is the code for rebooting the PC written in Turbo Pascal?
-
- A: This item draws from the information and the C-code example in
- Stan Brown's comp.os.msdos.programmer FAQ, garbo.uwasa.fi:
- /pc/doc-net/faqp9312.zip (at the time of writing this), from
- memory.lst and interrup.b in /pc/programming/inter35b.zip, and from
- /pc/programming/helppc21.zip. The Turbo Pascal code is my adaptation
- of the C-code. It is not a one-to-one replica.
- The usually advocated warm-boot method is storing $1234 in the
- word at $0040:$0072 and jumping to address $FFFF:$0000. The problem
- with this approach is that files must first be closed, potential
- caches flushed. This is how to do this
- procedure REBOOT;
- label next;
- var regs : registers;
- i : byte;
- ticks : longint;
- begin
- {... "press" alt-ctrl ...}
- mem[$0040:$0017] := mem[$0040:$0017] or $0C; { 00001100 }
- {... "press" del, try a few times ...}
- for i := 1 to 10 do
- begin
- FillChar (regs, sizeOf(regs), 0); { initialize }
- regs.ah := $4F; { service number }
- regs.al := $53; { del key's scan code }
- regs.flags := FCarry; { "sentinel for ignoring key" }
- Intr ($15, regs);
- {... check if the del key registered, if not retry ...}
- if regs.flags and Fcarry > 0 then goto next;
- {... waste some time, watch out for midnight ...}
- ticks := MemL [$0040:$006C];
- repeat until (MemL[$0040:$006C] - ticks > 3) or
- (MemL[$0040:$006C] - ticks < 0)
- end; {for}
- exit;
- next:
- {... disk reset: writes all modified disk buffers to disk ...}
- FillChar (regs, sizeOf(regs), 0);
- regs.ah := $0D;
- MsDos (regs);
- {... set post-reset flag, use $0000 instead of $1234 for coldboot ...}
- memW[$0040:$0072] := $1234;
- {... jump to $FFFF:0000 BIOS reset ...}
- Inline($EA/$00/$00/$FF/$FF);
- end; (* reboot *)
- One slight problem with this approach is that the keyboard intercept
- interrupt $15 service $4F requires at least an AT according to
- inter35b.zip. A simple test based on "FFFF:E byte ROM machine id"
- (the previous definition is from helppc21.zip) is:
- function ISATFN : boolean;
- begin
- case Mem[$F000:$FFFE] of
- $FC, $FA, $F8 : isatfn := true;
- else isatfn := false;
- end; {case}
- end; (* isatfn *)
- For a more comprehensive test use CPUFN "Get the type of the
- processor chip" from TSUNTH in garbo.uwasa.fi:/pc/ts/tspa*.zip.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:50 1993
- Subject: Writing inline code
-
- 50. *****
- Q: How can I write inline code?
-
- A: In Turbo Pascal versions prior 6.0 assembler code could not be
- directly included in the code. Instead one had to assemble the code
- into inline statements. Consider the task of rebooting the PC
- (without disk closing and cache flushing). The assemble code for
- this is
- mov ax,40
- mov ds,ax
- mov wo [72],1234
- jmp FFFF:0000
- To assemble this code into an inline statement write the following
- file calling it e.g. debug.in. The empty line is important.
- .... begin debug.in, cut here ....
- a 100
- mov ax,40
- mov ds,ax
- mov wo [72],1234
- jmp FFFF:0000
-
- u 100
- q
- .... end debug.in, cut here ....
- Give the following command
- debug < debug.in
- You'll get
- 0E9E:0100 B84000 MOV AX,0040
- 0E9E:0103 8ED8 MOV DS,AX
- 0E9E:0105 C70672003412 MOV WORD PTR [0072],1234
- 0E9E:010B EA0000FFFF JMP FFFF:0000
- This translates into
- Inline ($B8/$40/$00/
- $8E/$D8/
- $C7/$06/$72/$00/$34/$12/
- $EA/$00/$00/$FF/$FF);
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:51 1993
- Subject: Out of memory in compiling
-
- 51. *****
- Q: I am running out of memory when compiling my large program. What
- can I do?
-
- A: If you are compiling your program from within the IDE (the
- Integrated Development Environment) then select invoke the Option
- from the main menu, choose the Compiler item and set the Link buffer
- to Memory. (Also make the Compile option Destination to be Disk).
- If this is not sufficient, next resort to using the TPC command
- line version of the Turbo Pascal compiler instead of the IDE. Use
- the /L option ("Link buffer on disk"). Other users have also
- pointed to using the protected mode version, TPCX, if you have it.
- Divide your program into units. It is advisable anyway for
- modularity when your program size grows.
- I have no experience with this alternative, but other users have
- pointed that "If you have some extended memory, switch to BP", that
- is Borland Pascal 7.0.
-
- A2: If you would prefer compiling your program from within the IDE
- but cannot do it for the above reason (or if you would prefer to
- compile your program from within your favorite editor instead of the
- TP IDE) you can use the following trick. If your editor has a macro
- language like most good editors do, the assign a hotkey macro that
- compiles the current file with the TPC. If you are using SemWare's
- QEdit editor you'll find such a macro in garbo.uwasa.fi:/pc/ts/
- tsqed17.zip ("Macros and configurations for QEdit text-editor").
- Also your editor must be swapped to disk during the compilation
- if memory is critical. There is a very good program for doing that:
- /pc/sysutil/shroom2d.zip ("Shell Room, Swap to disk when shelling to
- application"). For example I invoke the QEdit editor with using the
- following batch:
- c:\tools\shroom -s r:\cmand -z 1024 c:\qedit\q %1 %2 %3 %4 %5 %6 %7
- You'll find more about the switches in the Shell Room documentation.
- The -s switch designates the swap destination (my r:\cmand directory
- is on my ramdisk). The -z switch sets the shell environment size.
- An unfortunate part is that the Turbo Pascal IDE is about the only
- program I know that is not amenable the to Shell Room utility, so
- you cannot utilize Shell Room to swap the TP IDE to disk.
- --------------------------------------------------------------------
-
- From ts@uwasa.fi Wed Aug 18 00:00:52 1993
- Subject: Last position write woes
-
- 52. *****
- Q: How do I avoid scrolling in the last column of the last row?
-
- A: If you use write or writeln at the last column of the last row
- (usually 80,25) the screen will scroll. If you wish to avoid the
- scrolling you'll have to use an alternative write that does not move
- the cursor. Here is a procedure to write without moving the cursor
- uses Dos;
- procedure WriteChar (Character : char; fgColor, bgColor : byte);
- var r : registers;
- begin
- FillChar (r, SizeOf(r), 0);
- r.ah := $09;
- r.al := ord(Character);
- r.bl := (bgColor shl 4) or fgColor;
- r.cx := 1; { Number of repeats }
- Intr ($10, r);
- end; (* writechar *)
- Thus, if you wish to write to the last column of the last row, you
- must first move the cursor to that position. That can be done in
- alternative ways. One might get there by having written previously
- on the screen (with writeln and write routines) until one is in that
- position. Another alternative is using GoToXY(80,20), but then you
- have to use the Crt unit. If you don't want to use it, then you can
- move the cursor by employing "GOATXY As the ordinary GoToXY but no
- Crt unit required" from garbo.uwasa.fi:/pc/ts/ tspa*.zip.
- There is an alternative interrupt service ($0A) which does the
- same as service $09, but uses the default colors instead. Just
- substitute $0A for $09, and leave the r.bl assignment out of the
- WriteChar routine.
- Another option for writing anyhere on the screen without
- affecting the cursor is using direct screen writes:
- uses Dos;
- procedure WriteChar (c : char; x, y : byte; fg, bg : byte);
- var vidstart : word;
- regs : registers;
- begin
- FillChar (regs, SizeOf(regs), 0);
- regs.ah := $0F;
- Intr ($10, regs); { Color or MonoChrome video adapter }
- if regs.al = 7 then vidstart := $B000 else vidstart := $B800;
- mem[vidstart:((y-1)*80+x-1)*2] := ord(c);
- mem[vidstart:((y-1)*80+x-1)*2+1] := (bg shl 4) or fg;
- end;
- To write to the last postion simply apply e.g.
- WriteChar ('X', 80, 25, 14, 0); { Yellow on black }
- The foreground (fg) and the background (bg) color codes are
- Black = 0
- Blue = 1
- Green = 2
- Cyan = 3
- Red = 4
- Magenta = 5
- Brown = 6
- LightGray = 7
- DarkGray = 8
- LightBlue = 9
- LightGreen = 10
- LightCyan = 11
- LightRed = 12
- LightMagenta = 13
- Yellow = 14
- White = 15
- Blink = 128
- --------------------------------------------------------------------
-